home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
- * is provided to you without charge, and with no warranty. You may give *
- * away copies of JOVE, including sources, provided that this notice is *
- * included in all the files. *
- ***************************************************************************/
-
- #include "jove.h"
- #include "fp.h"
- #include "termcap.h"
- #include "ctype.h"
- #include "chars.h"
- #include "disp.h"
- #include "re.h"
-
- #ifdef IPROCS
- # include <signal.h>
- #endif
-
- #ifdef MAC
- # include "mac.h"
- #else
- # ifdef STDARGS
- # include <stdarg.h>
- # else
- # include <varargs.h>
- # endif
- #endif
-
- #ifdef MSDOS
- # include <process.h>
- #endif
-
- private void
- DefAutoExec proto((struct data_obj *(*proc) ptrproto((const char *))));
-
- private int
- match proto((char **, char *));
-
- int InJoverc = 0;
-
- /* Auto execute code */
-
- #define NEXECS 20
-
- private struct {
- char *a_pattern;
- data_obj *a_cmd;
- } AutoExecs[NEXECS]; /* must be initialized by system to 0 */
-
- private int ExecIndex = 0;
-
- /* Command auto-execute. */
-
- void
- CAutoExec()
- {
- DefAutoExec(findcom);
- }
-
- /* Macro auto-execute. */
-
- void
- MAutoExec()
- {
- DefAutoExec(findmac);
- }
-
- private void
- DefAutoExec(proc)
- data_obj *(*proc) ptrproto((const char *));
- {
- data_obj *d;
- char *pattern;
- int i;
-
- if (ExecIndex >= NEXECS)
- complain("Too many auto-executes, max %d.", NEXECS);
- if ((d = (*proc)(ProcFmt)) == NULL)
- return;
- pattern = do_ask("\r\n", (bool (*) ptrproto((int))) NULL, (char *) NULL, ": %f %s ",
- d->Name);
- for (i = 0; i < ExecIndex; i++) {
- if (AutoExecs[i].a_cmd == d) {
- char *ipat = AutoExecs[i].a_pattern;
-
- if ((pattern == NULL || ipat == NULL)?
- (pattern == ipat) : (strcmp(pattern, ipat) == 0))
- return; /* eliminate duplicates */
- }
- }
- AutoExecs[ExecIndex].a_pattern = copystr(pattern);
- AutoExecs[ExecIndex].a_cmd = d;
- ExecIndex += 1;
- }
-
- /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
- same kind of file (i.e., match the same pattern) or OLD is NULL and it
- matches, OR if the pattern is NULL (none was specified) then, we execute
- the command associated with that kind of file. */
-
- void
- DoAutoExec(new, old)
- register char *new,
- *old;
- {
- register int i;
-
- set_arg_value(1);
- for (i = 0; i < ExecIndex; i++)
- if ((AutoExecs[i].a_pattern == NULL) ||
- ((new != NULL && LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
- (old == NULL || !LookingAt(AutoExecs[i].a_pattern, old, 0))))
- ExecCmd(AutoExecs[i].a_cmd);
- }
-
- int
- addgetc()
- {
- int c;
-
- if (!InJoverc) {
- Asking = YES;
- AskingWidth = strlen(mesgbuf);
- c = getch();
- Asking = NO;
- add_mess("%p ", c);
- } else {
- c = getch();
- if (c == '\n')
- return EOF; /* this isn't part of the sequence */
- else if (c == '\\') {
- if ((c = getch()) == LF)
- complain("[Premature end of line]");
- } else if (c == '^') {
- if ((c = getch()) == '?')
- c = RUBOUT;
- else if (jisalpha(c) || strchr("@[\\]^_", c))
- c = CTL(c);
- else
- complain("[Unknown control character]");
- }
- }
- return c;
- }
-
- void
- Extend()
- {
- data_obj *d;
-
- if ((d = findcom(": ")) != NULL)
- ExecCmd(d);
- }
-
- /* Read a positive integer from CP. It must be in base BASE, and
- complains if it isn't. If allints is nonzero, all the characters
- in the string must be integers or we return -1; otherwise we stop
- reading at the first nondigit. */
-
- int
- chr_to_int(cp, base, allints, result)
- register char *cp;
- int base,
- allints;
- register int *result;
- {
- register int c;
- int value = 0,
- sign;
-
- if ((c = *cp) == '-') {
- sign = -1;
- cp += 1;
- } else
- sign = 1;
- while ((c = *cp++) != '\0') {
- if (!jisdigit(c)) {
- if (allints == YES)
- return INT_BAD;
- break;
- }
- c = c - '0';
- if (c >= base)
- complain("You must specify in base %d.", base);
- value = value * base + c;
- }
- *result = value * sign;
- return INT_OKAY;
- }
-
- int
- ask_int(prompt, base)
- char *prompt;
- int base;
- {
- char *val = ask((char *)NULL, prompt);
- int value;
-
- if (chr_to_int(val, base, YES, &value) == INT_BAD)
- complain("That's not a number!");
- return value;
- }
-
- void
- vpr_aux(vp, buf, size)
- register const struct variable *vp;
- char *buf;
- size_t size;
- {
- switch (vp->v_flags & V_TYPEMASK) {
- case V_BASE10:
- swritef(buf, size, "%d", *((int *) vp->v_value));
- break;
-
- case V_BASE8:
- swritef(buf, size, "%o", *((int *) vp->v_value));
- break;
-
- case V_BOOL:
- swritef(buf, size, (*((int *) vp->v_value)) ? "on" : "off");
- break;
-
- case V_STRING:
- case V_FILENAME:
- swritef(buf, size, "%s", vp->v_value);
- break;
-
- case V_CHAR:
- swritef(buf, size, "%p", *((int *) vp->v_value));
- break;
- }
- }
-
- void
- PrVar()
- {
- struct variable *vp;
- char prbuf[256];
-
- if ((vp = (struct variable *) findvar(ProcFmt)) == NULL)
- return;
- vpr_aux(vp, prbuf, sizeof(prbuf));
- s_mess(": %f %s => %s", vp->Name, prbuf);
- }
-
- void
- SetVar()
- {
- struct variable *vp;
- char prompt[128];
-
- if ((vp = (struct variable *) findvar(ProcFmt)) == NULL)
- return;
- swritef(prompt, sizeof(prompt), ": %f %s ", vp->Name);
-
- switch (vp->v_flags & V_TYPEMASK) {
- case V_BASE10:
- case V_BASE8:
- *((int *) vp->v_value) = ask_int(prompt,
- ((vp->v_flags & V_TYPEMASK) == V_BASE10)? 10 : 8);
- break;
-
- case V_BOOL:
- {
- char *def = *((bool *) vp->v_value) ? "off" : "on",
- *on_off;
- bool value;
-
- on_off = ask(def, prompt);
- if (casecmp(on_off, "on") == 0)
- value = ON;
- else if (casecmp(on_off, "off") == 0)
- value = OFF;
- else {
- complain("Boolean variables must be ON or OFF.");
- /* NOTREACHED */
- }
- *((bool *) vp->v_value) = value;
- #ifdef MAC
- MarkVar(vp,-1,0); /* mark the menu item */
- #endif
- s_mess("%s%s", prompt, value ? "on" : "off");
- break;
- }
-
- case V_FILENAME:
- {
- char fbuf[FILESIZE];
- size_t pl = strlen(prompt);
-
- swritef(&prompt[pl], sizeof(prompt)-pl, "(default %s) ",
- (char *)vp->v_value);
- (void) ask_file(prompt, (char *) vp->v_value, fbuf);
- strcpy((char *) vp->v_value, fbuf);
- break;
- }
-
- case V_STRING:
- {
- char *str;
-
- /* Do_ask() so you can set string to "" if you so desire. */
- str = do_ask("\r\n", (bool (*) ptrproto((int))) NULL,
- (char *) vp->v_value, prompt);
- if (str == NULL)
- str = NullStr;
- strcpy((char *) vp->v_value, str);
- /* ... and hope there is enough room. */
- break;
- }
- case V_CHAR:
- f_mess(prompt);
- *((int *) vp->v_value) = addgetc();
- break;
-
- }
- if (vp->v_flags & V_MODELINE)
- UpdModLine = YES;
- if (vp->v_flags & V_CLRSCREEN) {
- #ifdef IBMPC
- setcolor(Fgcolor, Bgcolor);
- #endif /* IBMPC */
- ClAndRedraw();
- }
- if (vp->v_flags & V_TTY_RESET)
- tty_reset();
- }
-
- /* Command completion - possible is an array of strings, prompt is
- the prompt to use, and flags are ... well read jove.h.
-
- If flags are RET_STATE, and the user hits <return> what they typed
- so far is in the Minibuf string. */
-
- private char **Possible;
- private int comp_value,
- comp_flags;
-
- private bool
- aux_complete(c)
- int c;
- {
- int command,
- i;
-
- if (comp_flags & CASEIND) {
- char *lp;
-
- for (lp = linebuf; *lp != '\0'; lp++)
- if (jisupper(*lp))
- *lp = jtolower(*lp);
- }
- switch (c) {
- case EOF:
- comp_value = -1;
- return FALSE;
-
- case '\r':
- case '\n':
- command = match(Possible, linebuf);
- if (command >= 0) {
- comp_value = command;
- return FALSE; /* tells ask to stop */
- }
- if (eolp() && bolp()) {
- comp_value = NULLSTRING;
- return FALSE;
- }
- if (comp_flags & RET_STATE) {
- comp_value = command;
- return FALSE;
- }
- if (InJoverc)
- complain("[\"%s\" unknown]", linebuf);
- rbell();
- break;
-
- case '\t':
- case ' ':
- {
- int minmatch = 1000,
- maxmatch = 0,
- numfound = 0,
- lastmatch = -1,
- len = strlen(linebuf);
-
- for (i = 0; Possible[i] != 0; i++) {
- int this_len;
-
- this_len = numcomp(Possible[i], linebuf);
- maxmatch = max(maxmatch, this_len);
- if (this_len >= len) {
- if (numfound)
- minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
- else
- minmatch = strlen(Possible[i]);
- numfound += 1;
- lastmatch = i;
- if (strcmp(linebuf, Possible[i]) == 0)
- break;
- }
- }
-
- if (numfound == 0) {
- rbell();
- if (InJoverc)
- complain("[\"%s\" unknown]", linebuf);
- /* If we're not in the .joverc then
- let's do something helpful for the
- user. */
- if (maxmatch < len) {
- char *cp;
-
- cp = linebuf + maxmatch;
- *cp = '\0';
- Eol();
- }
- break;
- }
- if (c != '\t' && numfound == 1) {
- comp_value = lastmatch;
- return FALSE;
- }
- null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch);
- Eol();
- if (minmatch == len) /* No difference */
- rbell();
- break;
- }
-
- case '?':
- {
- int len;
-
- if (InJoverc)
- complain((char *)NULL);
- /* kludge: in case we're using UseBuffers, in which case
- linebuf gets written all over */
- strcpy(Minibuf, linebuf);
- len = strlen(Minibuf);
- TOstart("Completion", TRUE); /* for now ... */
- for (i = 0; Possible[i]; i++)
- if (numcomp(Possible[i], Minibuf) >= len) {
- Typeout(Possible[i]);
- if (TOabort)
- break;
- }
-
- TOstop();
- }
- break;
- }
- return TRUE;
- }
-
- int
- complete(possible, prompt, flags)
- register char *possible[];
- const char *prompt;
- int flags;
- {
- /* protect static "Possible" from being overwritten due to recursion */
- if (InRealAsk)
- complain((char *) NULL);
-
- Possible = possible;
- comp_flags = flags;
- (void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
- return comp_value;
- }
-
- private int
- match(choices, what)
- register char **choices,
- *what;
- {
- register size_t len;
- int i,
- found = 0,
- save = ORIGINAL,
- exactmatch = -1;
-
- len = strlen(what);
- if (len == 0)
- return NULLSTRING;
- for (i = 0; choices[i]; i++) {
- if (strncmp(what, choices[i], len) == 0) {
- if (choices[i][len] == '\0')
- exactmatch = i;
- save = i;
- found += 1; /* found one */
- }
- }
-
- if (found > 1) {
- if (exactmatch != -1)
- save = exactmatch;
- else
- save = AMBIGUOUS;
- }
-
- return save;
- }
-
- void
- Source()
- {
- char *com,
- buf[FILESIZE];
-
- #ifndef MSDOS
- swritef(buf, sizeof(buf), "%s/.joverc", HomeDir);
- #else /* MSDOS */
- if (com = getenv("JOVERC"))
- strcpy(buf, com);
- else
- strcpy(buf, Joverc);
- #endif /* MSDOS */
- com = ask_file((char *)NULL, buf, buf);
- if (!joverc(buf))
- complain(IOerr("read", com));
- }
-
- void
- BufPos()
- {
- register Line *lp = curbuf->b_first;
- register int i,
- dotline;
- long dotchar,
- nchars;
-
- for (i = nchars = 0; lp != NULL; i++, lp = lp->l_next) {
- if (lp == curline) {
- dotchar = nchars + curchar;
- dotline = i + 1;
- }
- nchars += length(lp) + (lp->l_next != NULL); /* include the NL */
- }
-
- s_mess("[\"%s\" line %d/%d, char %D/%D (%d%%), cursor = %d/%d]",
- filename(curbuf), dotline, i, dotchar, nchars,
- (nchars == 0) ? 100 : (int) (((long) dotchar * 100) / nchars),
- calc_pos(linebuf, curchar),
- calc_pos(linebuf, (int)strlen(linebuf)));
- }
-
- #ifndef MAC
- private int
- do_if(cmd)
- char *cmd;
- {
- int status;
- char *args[12];
-
- {
- char *cp = cmd,
- **ap = args;
-
- for (;;) {
- while (*cp == ' ')
- cp++;
- *ap++ = cp;
- if ((cp = strchr(cp, ' ')) == NULL)
- break;
- *cp++ = '\0';
- }
- ap[-1] = NULL;
- }
-
- #ifndef MSDOS
- {
- int pid;
-
- switch (pid = fork()) {
- case -1:
- complain("[Fork failed: if: %s]", strerror(errno));
- /*NOTREACHED*/
-
- case 0:
- close(0); /* we want reads to fail */
- /* close(1); but not writes or ioctl's
- close(2); */
- (void) execvp(args[0], (const char **)args);
- _exit(-10); /* signals exec error (see below) */
- /*NOTREACHED*/
- }
- #ifdef IPROCS
- SigHold(SIGCHLD);
- #endif
- dowait(pid, &status);
- #ifdef IPROCS
- SigRelse(SIGCHLD);
- #endif
- if (status == -10)
- complain("[Exec failed]");
- if (status < 0)
- complain("[Exit %d]", status);
- }
- #else /* MSDOS */
- if ((status = spawnvp(0, args[0], args)) < 0)
- complain("[Spawn failed: if]");
- #endif /* MSDOS */
-
- return (status == 0); /* 0 means successful */
- }
- #endif /* MAC */
-
- bool
- joverc(file)
- char *file;
- {
- char buf[LBSIZE],
- lbuf[LBSIZE];
-
- jmp_buf savejmp;
- volatile int lnum = 0;
- File *volatile fp;
- volatile bool eof;
- volatile unsigned int /* bitstrings */
- finger = 1,
- skipping = 0,
- inelse = 0;
-
- fp = open_file(file, buf, F_READ, NO, YES);
- if (fp == NULL)
- return NO; /* joverc returns an integer */
-
- /* Catch any errors, here, and do the right thing with them,
- and then restore the error handle to whoever did a setjmp
- last. */
-
- InJoverc += 1;
- push_env(savejmp);
- if (setjmp(mainjmp)) {
- Buffer *savebuf = curbuf;
-
- SetBuf(do_select((Window *)NULL, "RC errors"));
- ins_str(sprint("%s:%d:%s", pr_name(file, YES), lnum, lbuf), NO);
- ins_str(sprint("\t%s\n", mesgbuf), NO);
- unmodify();
- SetBuf(savebuf);
- Asking = NO;
- }
- do {
- /* This peculiar delayed EOF testing allows the last line to
- * end without a NL. We add NL later, so we leave room for it.
- */
- eof = f_gets(fp, lbuf, sizeof(lbuf)-1);
- lnum += 1;
- Inputp = lbuf;
- while (*Inputp == ' ' || *Inputp == '\t')
- Inputp += 1; /* skip white space */
- if (*Inputp == '#') {
- /* a comment */
- #ifndef MAC
- } else if (casencmp(Inputp, "if", (size_t)2) == 0) {
- finger <<= 1;
- if (finger == 0)
- complain("[`if' nested too deeply]");
- if (LookingAt("ifenv\\>[ \t]*\\<\\([^ \t][^ \t]*\\)\\>[ \t]\\(.*\\)$", Inputp, 0)) {
- if (skipping == 0) {
- char envname[128],
- envpat[128],
- *envval;
-
- putmatch(1, envname, sizeof envname);
- putmatch(2, envpat, sizeof envpat);
- envval = getenv(envname);
- if (envval==NULL || !LookingAt(envpat, envval, 0))
- skipping |= finger;
- }
- } else if (LookingAt("if\\>[ \t]*\\(.*\\)$", Inputp, 0)) {
- char cmd[128];
-
- putmatch(1, cmd, sizeof cmd);
- if (skipping == 0 && !do_if(cmd))
- skipping |= finger;
- } else {
- complain("[`if' syntax error]");
- }
- } else if (casecmp(Inputp, "else") == 0) {
- if (finger == 1 || (inelse & finger))
- complain("[Unexpected `else']");
- inelse |= finger;
- skipping ^= finger;
- } else if (casecmp(Inputp, "endif") == 0) {
- if (finger == 1)
- complain("[Unexpected `endif']");
- inelse &= ~finger;
- skipping &= ~finger;
- finger >>= 1;
- #endif
- } else if (skipping == 0) {
- (void) strcat(Inputp, "\n");
- Extend();
- if (Inputp) {
- while (*Inputp == ' ' || *Inputp == '\t')
- Inputp += 1; /* skip white space */
- if (*Inputp!='\0' && *Inputp!='\n')
- complain("[junk at end of line]");
- }
- }
- } while (!eof);
-
- f_close(fp);
- pop_env(savejmp);
- Inputp = NULL;
- Asking = NO;
- InJoverc -= 1;
- if (finger != 1)
- complain("[Missing endif]");
- return YES;
- }
-